// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 蜻蜓BSD系统调用。
// 该文件编译为普通Go代码，
// 但它也是mksyscall的输入，
// 解析
// 请注意，有时我们使用小写
// syscall_bsd.go或syscall_unix.go中。

package syscall

import (
	"sync"
	"unsafe"
)

// 参见中的版本列表https:
var (
	osreldateOnce sync.Once
	osreldate     uint32
)

// 2019年9月ABI变更
// http:
const _dragonflyABIChangeVersion = 500705

func supportsABI(ver uint32) bool {
	osreldateOnce.Do(func() { osreldate, _ = SysctlUint32("kern.osreldate") })
	return osreldate >= ver
}

type SockaddrDatalink struct {
	Len    uint8
	Family uint8
	Index  uint16
	Type   uint8
	Nlen   uint8
	Alen   uint8
	Slen   uint8
	Data   [12]int8
	Rcf    uint16
	Route  [16]uint16
	raw    RawSockaddrDatalink
}

// 将“kern.hostname”翻译成[]_C_int{0,1,2,3}。
func nametomib(name string) (mib []_C_int, err error) {
	const siz = unsafe.Sizeof(mib[0])

	// 注意（rsc）：将缓冲区设置为具有
	// 大小CTL_MAXNAME+2，但仅使用CTL_MAXNAME 
	// 作为大小似乎很奇怪。我不知道为什么这里有+2，但是
	// 内核使用+2来实现这个函数。
	// 我担心，如果我们不在这里包含+2，内核
	// 将默默地比我们指定的
	// 多写2个字，并且我们将得到内存损坏。
	var buf [CTL_MAXNAME + 2]_C_int
	n := uintptr(CTL_MAXNAME) * siz

	p := (*byte)(unsafe.Pointer(&buf[0]))
	bytes, err := ByteSliceFromString(name)
	if err != nil {
		return nil, err
	}

	// Magic sysctl:“设置”0.3为字符串名
	// 用于读回整数数组形式。
	if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil {
		return nil, err
	}
	return buf[0 : n/siz], nil
}

func direntIno(buf []byte) (uint64, bool) {
	return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
}

func direntReclen(buf []byte) (uint64, bool) {
	namlen, ok := direntNamlen(buf)
	if !ok {
		return 0, false
	}
	return (16 + namlen + 1 + 7) &^ 7, true
}

func direntNamlen(buf []byte) (uint64, bool) {
	return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}

// sysnb pipe（）（r int，w int，error error）

func Pipe(p []int) (err error) {
	if len(p) != 2 {
		return EINVAL
	}
	p[0], p[1], err = pipe()
	return
}

// sysnb pipe2（p*[2]\u C_int，flags int）（r int，w int，error error）

func Pipe2(p []int, flags int) (err error) {
	if len(p) != 2 {
		return EINVAL
	}
	var pp [2]_C_int
	// dragonfly上的pipe2将fds数组作为参数，但仍然返回文件描述符。
	p[0], p[1], err = pipe2(&pp, flags)
	return err
}

// sys extpread（fd int，p[]byte，flags int，offset int64）（n int，error error）
func Pread(fd int, p []byte, offset int64) (n int, err error) {
	return extpread(fd, p, 0, offset)
}

// sys extpwrite（fd int，p[]byte，flags int，offset int64）（n int，error error）
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
	return extpwrite(fd, p, 0, offset)
}

func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
	var rsa RawSockaddrAny
	var len _Socklen = SizeofSockaddrAny
	nfd, err = accept4(fd, &rsa, &len, flags)
	if err != nil {
		return
	}
	if len > SizeofSockaddrAny {
		panic("RawSockaddrAny too small")
	}
	sa, err = anyToSockaddr(&rsa)
	if err != nil {
		Close(nfd)
		nfd = 0
	}
	return
}

func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
	var _p0 unsafe.Pointer
	var bufsize uintptr
	if len(buf) > 0 {
		_p0 = unsafe.Pointer(&buf[0])
		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
	}
	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
	n = int(r0)
	if e1 != 0 {
		err = e1
	}
	return
}

func setattrlistTimes(path string, times []Timespec) error {
	// 用于达尔文的UtimesNano 
	return ENOSYS
}

/*
 * Exposed directly
 */
// sys Access（路径字符串，模式uint32）（error error）
// sys Chdir（路径字符串）（错误）
// sys Chflags（路径字符串，标志int）（错误）
// sys Chmod（路径字符串，模式uint32）（错误）
// sys Chown（路径字符串，uid int，gid int）（错误）
// sys-Fsync（fd-int）（error error）
// sys-Ftruncate（fd-int，length-int64）（error error）
// sysnb Getgid（）（gid int）
// sysnb Getpgid（pid int）（pgid int，error）
// sysnb Getpgrp（）（pgrp int）
// sys Getpriority（who int，who int）（prio int，error）
// sysnb Getrlimit（which int，lim*Rlimit）（error error）
// sysnb Getrusage（who int，rusage*rusage）（error error）
// sysnb Getsid（pid int）（sid int，error error）
// sysnb Getuid（）（uid int）
// sys Kill（pid int，signum Signal）（错误）
// sys Kqueue（）（fd int，error error）
// sys Lchown（path string，uid int，gid int）（error error）
// sys Link（path string，Link string）（error）
// sys Lstat（路径字符串，stat*stat_t）（错误）
// sys Mkdir（路径字符串，模式uint32）（错误）
// sys Mkfifo（路径字符串，模式uint32）（错误）
// /sys Open（路径字符串，模式int，perm uint32）（fd int，错误）
// sys Pathconf（path string，name int）（val int，error error）
// sys read（fd int，p[]byte）（n int，error）
// sys Readlink（path string，buf[]byte）（n int，error error）
// sys Rename（from string，to string）（error error）
// sys Rmdir（路径字符串）（错误）
// sys Seek（fd int，offset int64，whence int）（newoffset int64，error error）=sys LSEEK 
// sys Select（n int，r*FdSet，w*FdSet，e*FdSet，Timeval）（错误）
// sysnb Setgid（gid int）（error error）
// sys Setlogin（name string）（error error）
// sysnb Setpgid（pid int，pgid int）（error error error）
// sysnb Setreuid（ruid int，euid int）（error error）
// sysnb Setrlimit（which int，lim*Rlimit）（error error）
// sysnb setid（）（pid int，error error）
// sys Statfs（路径字符串，stat*Statfs\t）（错误）
// sys Symlink（路径字符串，链接字符串）（错误）
// sys Sync（）（错误）
// sys Truncate（路径字符串，长度int64）（错误）
// sys Undelete（路径字符串）（错误）
// sys Unlink（路径字符串）（错误）
// sys Unmount（路径字符串，标志int）（错误）
// sys write（fd int，p[]字节）（n int，错误）
// sys munmap（地址uintptr，长度uintptr）（err error）
// sys readlen（fd int，buf*字节，nbuf int）（n int，err err error）=sys READ 
// sys writelen（fd int，buf*字节，nbuf int err error）（n int，err err err error）=sys WRITE 
// 接受4（fd int，rsa*RawSockaddrAny，addrlen*_Socklen，flags int）（nfd int，error error）
// sys utimensat（dirfd int，path string，times*[2]Timespec，flag int）（error error）
